#ifndef _MUDUO_TCPCONNECTION_H_
#define _MUDUO_TCPCONNECTION_H_

#include "InetAddress.h"
#include "Buffer.h"
#include "Timestamp.h"
#include "copyable.h"
#include "FdEvent.h"

#include <memory>

namespace muduo
{

class LinkOwner;
class TcpLink;

typedef std::shared_ptr<TcpLink> TcpLinkSPtr;
typedef std::function<void (const TcpLinkSPtr&)> NewConnectionCallback;
typedef std::function<void (const TcpLinkSPtr&)> DelConnectionCallback;
typedef std::function<void (const TcpLinkSPtr&, Buffer*, Timestamp)> RcvMessageCallback;
typedef std::function<void (const TcpLinkSPtr&)> WriteCompleteCallback;
typedef std::function<void (const TcpLinkSPtr&, size_t)> HighWaterMarkCallback;

class TcpLink : public FdEvent,
                public std::enable_shared_from_this<TcpLink>
{
public:
    TcpLink(LinkOwner* owner, 
            const std::string& name,
            int sockfd,
            const InetAddress& localAddr,
            const InetAddress& peerAddr);
                  
    virtual ~TcpLink();
    
    virtual void handleRead(Timestamp& receiveTime);
    
    virtual void handleWrite();
    
    virtual void handleClose();
    
    virtual void handleError();

    void send(Buffer* buf);
    
    void send(const StringPiece& message);

    void sendInLoop(const StringPiece& message);
    
    void sendInLoop(const void* data, size_t len);
    
    static void bindSendInLoop(TcpLink* conn, const std::string& message);
    
    void shutdown();

    void shutdownInLoop();
    
    void forceClose();
    
    void forceCloseInLoop();    

    bool connected() const { return state_ == kConnected; }
    
    bool disconnected() const { return state_ == kDisconnected; }
  
    const std::string& name() const { return name_; }

    const InetAddress& peerAddr() const { return peerAddr_; }

    void setContext(void* context) { context_ = context; }

    void* getContext() { return context_; }
    
private:

    enum StateE { kDisconnected, kConnected, kDisconnecting };

    void setState(StateE s) { state_ = s; }
 
    StateE state_;
    
    LinkOwner* owner_;

    const std::string name_;
    
    const InetAddress localAddr_;
    
    const InetAddress peerAddr_;

    size_t highWaterMark_;
    
    Buffer inputBuffer_;
    
    Buffer outputBuffer_;

    void* context_;
};


}

#endif  // _MUDUO_TCPCONNECTION_H_
